/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Philippe Durand <draekz@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Runtime.InteropServices;
using System.Timers;

using Gtk;
using Cairo;

using Anculus.Core;

using Galaxium.Core;
//using Galaxium.GStreamer;
using Galaxium.Protocol;

namespace Galaxium.Gui.GtkGui
{
	public enum WebcamWidgetInfoMode { None, Entity, Control }
	
	public class WebcamWidget : EventBox
	{
		DrawingArea _drawArea = new DrawingArea ();
		//GStreamerVideoPlayer _video;
		ImageSurface _infoSurface = null;
		Tween _infoTween = new Tween ();
		WebcamWidgetInfoMode _infoMode = WebcamWidgetInfoMode.None;
		IEntity _entity;
		uint _scaleTimer;
		int _scaleWidth;
		int _scaleHeight;
		
		public WebcamWidgetInfoMode InfoMode
		{
			get { return _infoMode; }
			set
			{
				_infoMode = value;
				GenerateInfoSurface ();
			}
		}
		
		public IVideoPlayer VideoPlayer
		{
			get { return null;//_video; 
			}
		}
		
		public WebcamWidget (IEntity entity, bool local)
			: base ()
		{
			_entity = entity;
			
			try
			{
				//_video = VideoUtility.GetPlayer (local) as GStreamerVideoPlayer;
				//_video.NewFrame += VideoNewFrame;
			}
			catch (Exception ex)
			{
				//_video = null;
				
				Log.Error (ex, "Error initializing video");
			}
			
			_drawArea.ExposeEvent += DrawAreaExposeEvent;
			
			Add (_drawArea);
		}
		
		public void Play ()
		{
			//if (_video != null)
				//_video.Play ();
		}
		
		public void Stop ()
		{
			//if (_video != null)
				//_video.Stop ();
		}
		
		protected override void OnSizeAllocated (Gdk.Rectangle allocation)
		{
			base.OnSizeAllocated (allocation);
			GenerateInfoSurface ();
		}
		
		protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt)
		{
			bool ret = base.OnEnterNotifyEvent (evnt);
			_infoTween.Begin (0.8, 1000);
			return ret;
		}
		
		protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt)
		{
			bool ret = base.OnLeaveNotifyEvent (evnt);
			_infoTween.Begin (0, 500);
			return ret;
		}
		
		protected override void OnUnrealized ()
		{
			/*if (_video != null)
			{
				_video.NewFrame -= VideoNewFrame;
				_video.Close ();
				_video = null;
			}
			
			if (_infoSurface != null)
			{
				_infoSurface.Destroy ();
				_infoSurface = null;
			}*/
			
			base.OnUnrealized ();
		}
		
		void GenerateInfoSurface ()
		{
			//if (_video == null)
				return;
			
			if (_infoSurface != null)
				_infoSurface.Destroy ();
			
			if (_infoMode == WebcamWidgetInfoMode.None)
			{
				_infoSurface = null;
				return;
			}
			
			int infoHeight = 80;
			
			_infoSurface = new ImageSurface (Format.ARGB32, _drawArea.Allocation.Width, infoHeight);
			Context cx = new Context (_infoSurface);
			
			LinearGradient grad = new LinearGradient (0, 0, 0, infoHeight);
			grad.AddColorStop (0, new Color (0, 0, 0, 0));
			grad.AddColorStop (0.1, new Color (0.2, 0.2, 0.2, 0.4));
			grad.AddColorStop (1, new Color (0.3, 0.3, 0.3, 0.8));
			
			cx.Pattern = grad;
			cx.Paint ();
			
			int textX = 10;
			
			if ((_entity.DisplayImage != null) && (_entity.DisplayImage.ImageBuffer != null) && (_entity.DisplayImage.ImageBuffer.Length > 0))
			{
				try
				{
					Gdk.Pixbuf pBuf = new Gdk.Pixbuf (_entity.DisplayImage.ImageBuffer);
					Gdk.Pixbuf scaled = pBuf.ScaleSimple (60, 60, Gdk.InterpType.Bilinear);
					
					Gdk.CairoHelper.SetSourcePixbuf (cx, scaled, (infoHeight - scaled.Height) / 2, (infoHeight - scaled.Height) / 2);
					cx.Paint ();
					
					textX += scaled.Width + 10;
					
					scaled.Dispose ();
					pBuf.Dispose ();
				}
				catch
				{
				}
			}
			
			cx.SetFontSize (25);
			cx.MoveTo (textX, infoHeight - 35);
			cx.TextPath (_entity.DisplayIdentifier);
			cx.Color = new Color (1, 1, 1);
			cx.Fill ();
			
			cx.SetFontSize (12);
			cx.MoveTo (textX, infoHeight - 15);
			cx.TextPath (_entity.UniqueIdentifier);
			cx.Fill ();
			
			((IDisposable)cx).Dispose ();
		}
		
		void DrawAreaExposeEvent (object sender, ExposeEventArgs args)
		{
			Context cx = Gdk.CairoHelper.Create (args.Event.Window);
			
			int width = _drawArea.Allocation.Width;
			int height = _drawArea.Allocation.Height;
			
			cx.Color = new Color (0, 0, 0);
			cx.Paint ();
			
			/*if ((_video != null) && (_video.Surface != null))
			{
				double x = (width - _video.Width) / 2;
				double y = (height - _video.Height) / 2;
				
				cx.SetSourceSurface (_video.Surface, (int)x, (int)y);
				cx.Paint ();
				
				if ((_infoMode != WebcamWidgetInfoMode.None) && (_infoTween.Value > 0))
				{
					if (_infoSurface == null)
						GenerateInfoSurface ();
					
					cx.SetSourceSurface (_infoSurface, 0, height - _infoSurface.Height);
					cx.PaintWithAlpha (_infoTween.Value);
				}
			}
			else
			{
				cx.SetFontSize (20);
				
				TextExtents extents = cx.TextExtents (GettextCatalog.GetString ("No Video"));
				
				cx.MoveTo ((width - extents.Width) / 2, (height + extents.Height) / 2);
				cx.TextPath (GettextCatalog.GetString ("No Video"));
				
				cx.Color = new Color (1, 1, 1);
				cx.Fill ();
			}*/
			
			((IDisposable)cx.Target).Dispose ();
			((IDisposable)cx).Dispose ();
			
			args.RetVal = false;
		}
		
		void ScaleVideo (int width, int height)
		{
			_scaleWidth = width;
			_scaleHeight = height;
			
			if (_scaleTimer != 0)
				TimerUtility.ResetCallback (_scaleTimer);
			else _scaleTimer = TimerUtility.RequestCallback (delegate
			{
				//_video.SetScale (_scaleWidth, _scaleHeight);
				_scaleTimer = 0;
			}, 500);
		}
		
		void VideoNewFrame (object sender, ByteArrayEventArgs args)
		{
			//Log.Debug ("New Frame");
			
			/*int desiredWidth = (int)(((float)_video.Width / _video.Height) * _drawArea.Allocation.Height);
			
			if (desiredWidth != _drawArea.WidthRequest)
			{
				_drawArea.WidthRequest = desiredWidth;
				
				//TODO: This is a really ugly hack
				if (Parent is Viewport)
					(Parent as Viewport).WidthRequest = desiredWidth + 2;
				
				ScaleVideo (desiredWidth, _drawArea.Allocation.Height);
			}
			else
				_drawArea.QueueDraw ();*/
		}
	}
}
